package com.oneinlet

import java.text.SimpleDateFormat
import java.time.*
import java.time.temporal.ChronoUnit
import java.util.*
import java.util.Calendar


/**
 * 时间日期帮手，帮助你人性化简单处理各种常见时间运算，时间格式化需求
 * @see     java.math.Date
 * @author  WangZihe
 */
@Deprecated("不再维护此类，请参考使用YCLocalDateTime")
object YCDate {

    /**  按天换算毫秒数  **/
    private val DAY_IN_MILLIS = (24 * 3600 * 1000).toLong()
    /**  按小时换算毫秒数  **/
    private val HOUR_IN_MILLIS = (3600 * 1000).toLong()
    /**  按分钟换算毫秒数  **/
    private val MINUTE_IN_MILLIS = (60 * 1000).toLong()
    /**  按秒换算毫秒数  **/
    private val SECOND_IN_MILLIS: Long = 1000

    enum class DateFormat(val style: String) {
        YYYY_MM_DD_HH_MM_SS("yyyy-MM-dd HH:mm:ss"),
        YYYY_MM_DD("yyyy-MM-dd"),
        YYYY_MM_DD_HH_MM_SS_SSS("yyyy-MM-dd HH:mm:ss.SSS"),
        YYYY_YEAR_MM_MONTH_DD_DAY("yyyy年MM月dd日"),
        YYYYMMDDHHMMSS("yyyyMMddHHmmss"),
    }

    enum class DateUnit {
        YEAR,
        MONTH,
        DAY,
        HOUR,
        MINUTE,
        SECOND,
        MILLISECOND
    }

    enum class DateNode {
        START,
        END
    }

    /**
     * 将时间进行格式化
     * @param date  接收一个Date对象
     * @return  返回一个格式化后的日期字符串
     * */
    fun formatDate(date: Date, dateFormat: DateFormat = DateFormat.YYYY_MM_DD_HH_MM_SS): String {
        return SimpleDateFormat(dateFormat.style).format(date)
    }

    /**
     * 将时间进行格式化
     * @param style  保证扩展性，接受一个格式化日期字符串
     * @return  返回一个格式化后的日期字符串
     * */
    fun formatDate(date: Date, style: String): String {
        return SimpleDateFormat(style).format(date)
    }

    /**
     * 将字符串时间解析成日期对象
     * @param date  保证扩展性，接受一个格式化日期枚举
     * @return  返回一个日期对象
     * */
    fun parserDate(date: String, dateFormat: DateFormat): Date {
        return SimpleDateFormat(dateFormat.style).parse(date)
    }

    /**
     * 将字符串时间解析成日期对象
     * @param style  保证扩展性，接受一个格式化日期字符串
     * @return  返回一个日期对象
     * */
    fun parserDate(date: String, style: String): Date {
        return SimpleDateFormat(style).parse(date)
    }

    /**
     * 对年月日时分秒毫秒设置指定数字
     * @param date  接收一个Date对象
     * @param amount  接收一个整型，例如 数字是1 单位是月  则表示该日期时间的月份为1
     * @param dateUnit  接收一个时间单位，表示对该时间单位进行加减运算
     * @return  返回一个设置过后的日期
     * */
    fun setDate(date: Date, amount: Int, dateUnit: DateUnit): Date {
        val c = Calendar.getInstance()
        c.isLenient = false
        c.time = date

        when (dateUnit) {
            DateUnit.YEAR -> {
                c.set(Calendar.YEAR, amount)
            }
            DateUnit.MONTH -> {
                // 月份是从0开始排序的，0代表1月份，1代表2月份，保证可读性，我们按照常规思维设置即可
                c.set(Calendar.MONTH, amount - 1)
            }
            DateUnit.DAY -> {
                c.set(Calendar.DAY_OF_MONTH, amount)
            }
            DateUnit.HOUR -> {
                c.set(Calendar.HOUR_OF_DAY, amount)
            }
            DateUnit.MINUTE -> {
                c.set(Calendar.MINUTE, amount)
            }
            DateUnit.SECOND -> {
                c.set(Calendar.SECOND, amount)

            }
            DateUnit.MILLISECOND -> {
                c.set(Calendar.MILLISECOND, amount)
            }
        }
        return c.time
    }

    /**
     * 对年月日时分秒毫秒进行加减, 减法为负数
     * @param date  接收一个Date对象
     * @param amount  接收一个整型，负数为减，正数为加
     * @param dateUnit  接收一个时间单位，表示对该时间单位进行加减运算
     * @return  返回一个计算过后的日期
     * */
    fun addDate(date: Date, amount: Int, dateUnit: DateUnit): Date {
        val c = Calendar.getInstance()
        c.time = date
        when (dateUnit) {
            DateUnit.YEAR -> {
                c.add(Calendar.YEAR, amount)
            }
            DateUnit.MONTH -> {
                c.add(Calendar.MONTH, amount)
            }
            DateUnit.DAY -> {
                c.add(Calendar.DAY_OF_MONTH, amount)
            }
            DateUnit.HOUR -> {
                c.add(Calendar.HOUR_OF_DAY, amount)
            }
            DateUnit.MINUTE -> {
                c.add(Calendar.MINUTE, amount)
            }
            DateUnit.SECOND -> {
                c.add(Calendar.SECOND, amount)
            }
            DateUnit.MILLISECOND -> {
                c.add(Calendar.MILLISECOND, amount)
            }
        }
        return c.time
    }


    /**
     * 对时间进行差值计算
     * @param leftDate  接收一个Date对象
     * @param rightDate  接收一个Date对象
     * @param dateUnit  接收一个时间单位，返回该对应单位的差值
     * @return  返回一个格式化后的日期字符串
     * */
    fun diffBetweenDate(leftDate: Date, rightDate: Date, dateUnit: DateUnit): Long {
        val leftLocalDateTime = dateToLocalDateTime(leftDate)
        val rightLocalDateTime = dateToLocalDateTime(rightDate)
        return diffBetweenDate(leftLocalDateTime, rightLocalDateTime, dateUnit)
    }

    /**
     * 对时间进行差值计算
     * @param leftLocalDateTime  接收一个LocalDateTime对象
     * @param rightLocalDateTime  接收一个LocalDateTime对象
     * @param dateUnit  接收一个时间单位，返回该对应单位的差值
     * @return  返回一个格式化后的日期字符串
     * */
    fun diffBetweenDate(leftLocalDateTime: LocalDateTime, rightLocalDateTime: LocalDateTime, dateUnit: DateUnit): Long {
        return when (dateUnit) {
            DateUnit.YEAR -> {
                ChronoUnit.YEARS.between(leftLocalDateTime, rightLocalDateTime)
            }
            DateUnit.MONTH -> {
                ChronoUnit.MONTHS.between(leftLocalDateTime, rightLocalDateTime)
            }
            DateUnit.DAY -> {
                ChronoUnit.DAYS.between(leftLocalDateTime, rightLocalDateTime)
            }
            DateUnit.HOUR -> {
                Duration.between(leftLocalDateTime, rightLocalDateTime).toHours()
            }
            DateUnit.MINUTE -> {
                Duration.between(leftLocalDateTime, rightLocalDateTime).toMinutes()
            }
            DateUnit.SECOND -> {
                Duration.between(leftLocalDateTime, rightLocalDateTime).seconds
            }
            DateUnit.MILLISECOND -> {
                Duration.between(leftLocalDateTime, rightLocalDateTime).toMillis()
            }
        }
    }

    /**
     * 将date对象转换为LocalDateTime对象
     * @param date  接受date对象
     * @return  返回一个LocalDateTime日期对象
     * */
    fun dateToLocalDateTime(date: Date): LocalDateTime {
        val cal = Calendar.getInstance()
        cal.time = date
        val year = cal.get(Calendar.YEAR)
        val month = cal.get(Calendar.MONTH) + 1
        val day = cal.get(Calendar.DATE)
        val hour = cal.get(Calendar.HOUR_OF_DAY)//24小时制
        val minute = cal.get(Calendar.MINUTE)
        val second = cal.get(Calendar.SECOND)
        val millis = cal.get(Calendar.MILLISECOND)
        return LocalDateTime.of(year, month, day, hour, minute, second, millis)
    }

    /**
     * 将date对象转换为LocalDate对象
     * @param Date  接受date对象
     * @return  返回一个LocalDate日期对象
     * */
    fun dateToLocalDate(date: Date): LocalDate {
        val cal = Calendar.getInstance()
        cal.time = date
        val year = cal.get(Calendar.YEAR)
        val month = cal.get(Calendar.MONTH)
        val day = cal.get(Calendar.DATE)
        return LocalDate.of(year, month, day)
    }

    /**
     * 判断当前时间是否在这个区间时间范围内，默认是大于等于起始时间并且小于等于结束时间
     * @param date  计划目标时间
     * @param startDate  起始时间
     * @param endDate  结束时间
     * @return  返回布尔值，true即在此范围区间内，false不在
     * */
    fun dateAtBetween(date: Date, startDate: Date, endDate: Date): Boolean {
        if (date in startDate..endDate) {
            return true
        }
        return false
    }

    /**
     * 判断当前时间是否在这个区间时间范围内，默认是大于等于起始时间并且小于等于结束时间
     * @param date  计划目标时间
     * @param startDate  起始时间
     * @param endDate  结束时间
     * @return  返回布尔值，true即在此范围区间内，false不在
     * */
    fun dateAtBetween(date: LocalDateTime, startDate: LocalDateTime, endDate: LocalDateTime): Boolean {
        if (date in startDate..endDate) {
            return true
        }
        return false
    }

    /**
     *  获取所在时间内当天的开始或者结束时间节点
     * @param date  指定当前时间
     * @param dateNode  时间节点，是起点时间还是结束的时间
     * */
    fun getTimeNodeWithDay(date: Date, dateNode: DateNode): Date {
        var newDate = date
        when (dateNode) {
            DateNode.START -> {
                newDate = setDate(date, 0, DateUnit.HOUR)
                newDate = setDate(newDate, 0, DateUnit.MINUTE)
                newDate = setDate(newDate, 0, DateUnit.SECOND)
            }
            DateNode.END -> {
                newDate = setDate(date, 23, DateUnit.HOUR)
                newDate = setDate(newDate, 59, DateUnit.MINUTE)
                newDate = setDate(newDate, 59, DateUnit.SECOND)
            }
        }
        return newDate
    }
    /**
     *  将秒数转换为时分秒，通常用于倒计时操作
     * @param secondParameter  指定当前秒数，必须是大于0
     * @return LocalTime  返回一个时间 如 02:30:59sha
     * */
    fun secondToDayTime(secondParameter: Int): LocalTime {
        YCAssert.isTrue(secondParameter >= 0, "秒数不能小于等于0")
        var hour: Int
        var minute: Int
        var second: Int
        hour = secondParameter / 3600
        minute = (secondParameter - hour * 3600) / 60
        second = secondParameter - hour * 3600 - minute * 60
        return LocalTime.of(hour, minute, second)
    }

}